<script setup lang='ts'>
import { ref, nextTick } from 'vue'
import list from './components/list.vue';
import { reqChat } from '@/apis/ai';
import type { messagesState } from './type/messageState'
import { ElMessage } from 'element-plus';
import axios from 'axios';
import type { CancelTokenSource } from 'axios';
import { Plus } from '@element-plus/icons-vue'

// 最大历史记录字符长度
const MAX_CONTEXT_LENGTH = 3000
const inputValue = ref<string>('')
const answerRef = ref<HTMLDivElement>()
const isThinking = ref<boolean>(false)
const timerId = ref<number | undefined>()
const cancelTokenSource = ref<CancelTokenSource | null>(null)
const messageList = ref<messagesState[]>([{
  role: 'assistant',
  content: '你好，我是Ai助手，请问有什么可以帮助你的吗？',
  isLoading: false
}])


// 生成历史记录
const generateContext = () => {
  let context = []
  let totalLength = 0

  // 逆序处理
  const reversedMessages = [...messageList.value].reverse()

  for (const msg of reversedMessages) {
    if (msg.isLoading) continue

    const content = `${msg.content}`
    if (totalLength + content.length > MAX_CONTEXT_LENGTH) break

    // 恢复正序
    context.unshift({
      role: msg.role === 'user' ? 'user' : 'assistant',
      content: content
    })
    totalLength += content.length
  }

  return context
}

// 滚动到消息容器底部
const scrollToBottom = async () => {
  await nextTick()
  if (answerRef.value) {
    answerRef.value.scrollTop = answerRef.value.scrollHeight
  }
}

// 流式更新
const updateAnswer = (aiResponse: messagesState, response: string) => {
  let index = 0
  // 利用定时器模拟打字效果
  timerId.value = setInterval(() => {
    if (index < response.length) {
      messageList.value = messageList.value.map((msg: messagesState) => {
        return msg.id === aiResponse.id ? {
          ...msg,
          content: response.slice(0, index + 1),
          isLoading: false
        } : { ...msg }
      })
      index++
      scrollToBottom()
    } else {
      clearInterval(timerId.value)
      timerId.value = undefined
      isThinking.value = false
    }
  }, 50)
}

// 发送问题
// 修改请求处理部分
// const webSocket = ref<WebSocket | null>(null)

// const handlerSubmit = async () => {
//   if (inputValue.value.trim()) {
//     isThinking.value = true
//     // 回显问题
//     messageList.value.push({
//       role: 'user',
//       content: inputValue.value
//     })
//     await scrollToBottom()
//     inputValue.value = '' 
    
//     // 创建AI响应条目
//     const aiResponse = {
//       role: 'assistant',
//       content: '',
//       isLoading: true,
//       id: Date.now()
//     }
//     messageList.value.push(aiResponse)
//     scrollToBottom()

//     try {
//       // 创建WebSocket连接
//       webSocket.value = new WebSocket('ws://172.21.160.101:11434/api')

//       webSocket.value.onmessage = (event) => {
//         const response = JSON.parse(event.data)
//         messageList.value = messageList.value.map((msg: messagesState) => {
//           if (msg.id === aiResponse.id) {
//             return {
//               ...msg,
//               content: msg.content + response.content,
//               isLoading: false
//             }
//           }
//           return msg
//         })
//         scrollToBottom()
//       }

//       webSocket.value.onerror = (error) => {
//         console.error('WebSocket error:', error)
//         isThinking.value = false
//       }

//       webSocket.value.onclose = () => {
//         isThinking.value = false
//       }

//       // 发送上下文
//       webSocket.value.onopen = () => {
//         webSocket.value?.send(JSON.stringify({
//         "model": "deepseek-r1:70b",
//         "messages": [
//           ...generateContext()
//         ],
//         "stream": true
//       }))
//       }

//     } catch (error) {
//       messageList.value = messageList.value.map((msg: messagesState) => {
//         return msg.id === aiResponse.id ? {
//           ...msg,
//           isLoading: false,
//           content: '连接失败'
//         } : { ...msg }
//       })
//       isThinking.value = false
//     }
//   } else {
//     ElMessage.error('请勿发送空白内容')
//   }
// }

const handlerSubmit = async () => {
  if (inputValue.value.trim()) {
    isThinking.value = true
    // 创建cancelTokenSource用于取消请求
    cancelTokenSource.value = axios.CancelToken.source()
    // 回显问题
    messageList.value.push({
      role: 'user',
      content: inputValue.value
    })
    await scrollToBottom()
    inputValue.value = ''
    // 添加loading
    const aiResponse = {
      role: 'assistant',
      content: '',
      isLoading: true,
      id: Date.now()
    }
    messageList.value.push(aiResponse)
    scrollToBottom()
    try {
      const res = await reqChat({
        "model": "deepseek-r1:70b",
        "messages": [
          ...generateContext()
        ],
        "stream": false
      }, {
        // 添加cancelToken配置
        cancelToken: cancelTokenSource.value.token
      })
      updateAnswer(aiResponse, res.message.content)
    } catch (error) {
      // console.log(axios.isCancel(error))
      if (!axios.isCancel(error)) {
        messageList.value = messageList.value.map((msg: messagesState) => {
          return msg.id === aiResponse.id ? {
            ...msg,
            isLoading: false,
            content: '请求失败'
          } : { ...msg }
        })
        isThinking.value = false
      }
    }
  } else {
    ElMessage({
      message: '请勿发送空白内容',
      type: 'error',
    })
  }
}

// 修改停止处理
// const handlerStop = () => {
//   if (webSocket.value) {
//     webSocket.value.close()
//     webSocket.value = null
//   }
  
//   const lastMessage = messageList.value[messageList.value.length - 1]
//   if (lastMessage.isLoading) {
//     messageList.value = messageList.value.map((msg: messagesState) => {
//       return msg.id === lastMessage.id ? {
//         ...msg,
//         isLoading: false,
//         content: '已停止思考'
//       } : { ...msg }
//     })
//   }
//   isThinking.value = false
// }


// 停止思考
const handlerStop = () => {
  if (timerId.value) {
    clearInterval(timerId.value)
    timerId.value = undefined
  }

  const lastMessage = messageList.value[messageList.value.length - 1]
  if (lastMessage.isLoading) {
    messageList.value = messageList.value.map((msg: messagesState) => {
      return msg.id === lastMessage.id ? {
        ...msg,
        isLoading: false,
        content: '已停止思考'
      } : { ...msg }
    })
  }
  isThinking.value = false

  if (cancelTokenSource.value) {
    cancelTokenSource.value.cancel('用户主动停止')
    cancelTokenSource.value = null
  }
}

// 开启新的对话
const handlderNewChat = () => {
  handlerStop()
    messageList.value = [{
    role: 'assistant',
    content: '你好，我是Ai助手，请问有什么可以帮助你的吗？',
    isLoading: false
  }]
}
</script>


<template>
  <div class="container">
    <div class="top">
      <h1>JYUChat</h1>
    </div>
    <div class="inner">
      <div class="answer" ref="answerRef">
        <list :messages="messageList" />
      </div>
    </div>
    <div class="bottom">
      <div class="new_chat">
        <el-button type="primary" round :icon="Plus" @click="handlderNewChat">开启新的对话</el-button>
      </div>
      <div class="request">
        <textarea v-model="inputValue" type="text" placeholder="请输入问题"
          @keydown.enter.exact.prevent="isThinking ? handlerStop() : handlerSubmit()" />
        <el-button class="btn" type="primary" @click="handlerSubmit" v-if="!isThinking">发送问题</el-button>
        <el-button class="btn" type="danger" @click="handlerStop" v-else>停止思考</el-button>
      </div>
    </div>
  </div>
</template>


<style scoped lang='scss'>
.container {

  .top {
    height: 60px;

    h1 {
      text-align: center;
    }
  }

  .inner {
    height: 550px;

    .answer {
      border: 1px solid #f9f9f9;
      width: 800px;
      height: 500px;
      margin: 0 auto;
      border-radius: 4px;
      overflow-y: auto;
      padding: 20px;

      // 修改滚动条样式
      &::-webkit-scrollbar {
        width: 6px;
        height: 6px;
      }

      &::-webkit-scrollbar-track {
        background: #f1f1f1;
        border-radius: 3px;
      }

      &::-webkit-scrollbar-thumb {
        background: #c1c1c1;
        border-radius: 3px;

        &:hover {
          background: #a8a8a8;
        }
      }
    }

    .item_ai,
    .item_user {
      margin-bottom: 15px;
      min-height: 50px;
    }
  }

  .bottom {
    margin-top: 20px;
    height: 170px;

    .new_chat {
      margin: 10px;
      text-align: center;

    }

    .request {
      position: relative;
      border: 1px solid #f9f9f9;
      background-color: #fff;
      width: 800px;
      height: 150px;
      margin: 0 auto;
      border-radius: 13px;

      textarea {
        padding: 10px;
        border: none;
        outline: none;
        resize: none;
        width: 780px;
        height: 80px;
        white-space: pre-wrap;
        overflow-y: auto;
        font-size: 20px;
        // 背景透明
        background: transparent;
      }

      .btn {
        position: absolute;
        right: 20px;
        bottom: 15px;
      }
    }
  }
}
</style>